home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / nethack.lha / nethack-3.1 / src / mkmaze.c < prev    next >
C/C++ Source or Header  |  1993-01-18  |  29KB  |  1,215 lines

  1. /*    SCCS Id: @(#)mkmaze.c    3.1    93/01/17    */
  2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. #include "hack.h"
  6. #include "sp_lev.h"
  7.  
  8. #define    UP    1
  9. #define DOWN    0
  10.  
  11. /* from sp_lev.c, for fixup_special() */
  12. extern char *lev_message;
  13. extern lev_region *lregions;
  14. extern int num_lregions;
  15.  
  16. static int FDECL(iswall,(int,int));
  17. static boolean FDECL(okay,(int,int,int));
  18. static void FDECL(maze0xy,(coord *));
  19. static boolean FDECL(put_lregion_here,(XCHAR_P,XCHAR_P,XCHAR_P,
  20.     XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P,BOOLEAN_P,d_level *));
  21. static void NDECL(fixup_special);
  22. static void NDECL(setup_waterlevel);
  23. static void NDECL(unsetup_waterlevel);
  24.  
  25. static int
  26. iswall(x,y)
  27. int x,y;
  28. {
  29.     if (x<=0 || y<0 || x>COLNO-1 || y>ROWNO-1)
  30.         return 0;
  31.     return (IS_WALL(levl[x][y].typ) || IS_DOOR(levl[x][y].typ)
  32.         || levl[x][y].typ == SDOOR);
  33. }
  34.  
  35. void
  36. wallification(x1, y1, x2, y2)
  37. int x1, y1, x2, y2;
  38. {
  39.     uchar type;
  40.     short x,y;
  41.     register struct rm *lev;
  42.  
  43.     if (x1 < 0) x1 = 0;
  44.     if (x2 < x1) x2 = x1;
  45.     if (x2 > COLNO-1) x2 = COLNO-1;
  46.     if (x1 > x2) x1 = x2;
  47.     if (y1 < 0) y1 = 0;
  48.     if (y2 < y1) y2 = y1;
  49.     if (y2 > ROWNO-1) y2 = ROWNO-1;
  50.     if (y1 > y2) y1 = y2;
  51.     for(x = x1; x <= x2; x++)
  52.         for(y = y1; y <= y2; y++) {
  53.         lev = &levl[x][y];
  54.         type = lev->typ;
  55.         if (iswall(x,y)) {
  56.           if (IS_DOOR(type) || type == SDOOR || type == DBWALL)
  57.             continue;
  58.           else
  59.             if (iswall(x,y-1))
  60.             if (iswall(x,y+1))
  61.                 if (iswall(x-1,y))
  62.                 if (iswall(x+1,y))
  63.                     lev->typ = CROSSWALL;
  64.                 else
  65.                     lev->typ = TLWALL;
  66.                 else
  67.                 if (iswall(x+1,y))
  68.                     lev->typ = TRWALL;
  69.                 else
  70.                     lev->typ = VWALL;
  71.             else
  72.                 if (iswall(x-1,y))
  73.                 if (iswall(x+1,y))
  74.                     lev->typ = TUWALL;
  75.                 else
  76.                     lev->typ = BRCORNER;
  77.                 else
  78.                 if (iswall(x+1,y))
  79.                     lev->typ = BLCORNER;
  80.                 else
  81.                     lev->typ = VWALL;
  82.             else
  83.             if (iswall(x,y+1))
  84.                 if (iswall(x-1,y))
  85.                 if (iswall(x+1,y))
  86.                     lev->typ = TDWALL;
  87.                 else
  88.                     lev->typ = TRCORNER;
  89.                 else
  90.                 if (iswall(x+1,y))
  91.                     lev->typ = TLCORNER;
  92.                 else
  93.                     lev->typ = VWALL;
  94.             else
  95.                 lev->typ = HWALL;
  96.         }
  97.         }
  98. }
  99.  
  100. static boolean
  101. okay(x,y,dir)
  102. int x,y;
  103. register int dir;
  104. {
  105.     move(&x,&y,dir);
  106.     move(&x,&y,dir);
  107.     if(x<3 || y<3 || x>x_maze_max || y>y_maze_max || levl[x][y].typ != 0)
  108.         return(FALSE);
  109.     return(TRUE);
  110. }
  111.  
  112. static void
  113. maze0xy(cc)    /* find random starting point for maze generation */
  114.     coord    *cc;
  115. {
  116.     cc->x = 3 + 2*rn2((x_maze_max>>1) - 1);
  117.     cc->y = 3 + 2*rn2((y_maze_max>>1) - 1);
  118.     return;
  119. }
  120.  
  121. /*
  122.  * Bad if:
  123.  *    pos is occupied OR
  124.  *    pos is inside restricted region (lx,ly,hx,hy) OR
  125.  *    NOT (pos is corridor and a maze level OR pos is a room OR pos is air)
  126.  */
  127. boolean
  128. bad_location(x, y, lx, ly, hx, hy)
  129.     xchar x, y;
  130.     xchar lx, ly, hx, hy;
  131. {
  132.     return(occupied(x, y) ||
  133.        ((x >= lx) && (x <= hx) && (y >= ly) && (y <= hy)) ||
  134.        !((levl[x][y].typ == CORR && level.flags.is_maze_lev) ||
  135.            levl[x][y].typ == ROOM || levl[x][y].typ == AIR));
  136. }
  137.  
  138. /* pick a location in area (lx, ly, hx, hy) but not in (nlx, nly, nhx, nhy) */
  139. /* and place something (based on rtype) in that region */
  140. void
  141. place_lregion(lx, ly, hx, hy, nlx, nly, nhx, nhy, rtype, lev)
  142.     xchar    lx, ly, hx, hy;
  143.     xchar    nlx, nly, nhx, nhy;
  144.     xchar    rtype;
  145.     d_level    *lev;
  146. {
  147.     int trycnt;
  148.     boolean oneshot;
  149.     xchar x, y;
  150.  
  151.     if(!lx) { /* default to whole level */
  152.     /*
  153.      * if there are rooms and this a branch, let place_branch choose
  154.      * the branch location (to avoid putting branches in corridors).
  155.      */
  156.     if(rtype == LR_BRANCH && nroom) {
  157.         place_branch(Is_branchlev(&u.uz), 0, 0);
  158.         return;
  159.     }
  160.  
  161.     lx = 1; hx = COLNO-1;
  162.     ly = 1; hy = ROWNO-1;
  163.     }
  164.  
  165.     /* first a probabilistic approach */
  166.  
  167.     oneshot = (lx == hx && ly == hy);
  168.     for(trycnt = 0; trycnt < 100; trycnt ++) {
  169.  
  170.     x = rn1((hx - lx) + 1, lx);
  171.     y = rn1((hy - ly) + 1, ly);
  172.  
  173.     if (put_lregion_here(x,y,nlx,nly,nhx,nhy,rtype,oneshot,lev))
  174.         return;
  175.     }
  176.  
  177.     /* then a deterministic one */
  178.  
  179.     oneshot = TRUE;
  180.     for (x = lx; x <= hx; x++)
  181.     for (y = ly; y <= hy; y++)
  182.         if (put_lregion_here(x,y,nlx,nly,nhx,nhy,rtype,oneshot,lev))
  183.         return;
  184.  
  185.     impossible("Couldn't place lregion type %d!", rtype);
  186. }
  187.  
  188. static boolean
  189. put_lregion_here(x,y,nlx,nly,nhx,nhy,rtype,oneshot,lev)
  190. xchar x, y;
  191. xchar nlx, nly, nhx, nhy;
  192. xchar rtype;
  193. boolean oneshot;
  194. d_level *lev;
  195. {
  196.     if(oneshot) {
  197.     /* must make due with the only location possible */
  198.     /* avoid failure due to a misplaced trap */
  199.     /* it might still fail if there's a dungeon feature here */
  200.     struct trap *t = t_at(x,y);
  201.     if (t) deltrap(t);
  202.     }
  203.     if(bad_location(x, y, nlx, nly, nhx, nhy)) return(FALSE);
  204.     switch (rtype) {
  205.     case LR_TELE:
  206.     case LR_UPTELE:
  207.     case LR_DOWNTELE:
  208.     /* "something" means the player in this case */
  209.     if(MON_AT(x, y)) {
  210.         /* move the monster if no choice, or just try again */
  211.         if(oneshot) rloc(m_at(x,y));
  212.         else return(FALSE);
  213.     }
  214.     u.ux = x; u.uy = y;
  215.     break;
  216.     case LR_PORTAL:
  217.     mkportal(x, y, lev->dnum, lev->dlevel);
  218.     break;
  219.     case LR_DOWNSTAIR:
  220.     case LR_UPSTAIR:
  221.     mkstairs(x, y, (char)rtype, (struct mkroom *)0);
  222.     break;
  223.     case LR_BRANCH:
  224.     place_branch(Is_branchlev(&u.uz), x, y);
  225.     break;
  226.     }
  227.     return(TRUE);
  228. }
  229.  
  230. static boolean was_waterlevel; /* ugh... this shouldn't be needed */
  231.  
  232. /* this is special stuff that the level compiler cannot (yet) handle */
  233. static void
  234. fixup_special()
  235. {
  236.     register lev_region *r = lregions;
  237.     struct d_level lev;
  238.     register int x, y;
  239.     struct mkroom *croom;
  240.     boolean added_branch = FALSE;
  241.  
  242.     if (was_waterlevel) {
  243.     was_waterlevel = FALSE;
  244.     u.uinwater = 0;
  245.     unsetup_waterlevel();
  246.     } else if (Is_waterlevel(&u.uz)) {
  247.     level.flags.hero_memory = 0;
  248.     was_waterlevel = TRUE;
  249.     /* water level is an odd beast - it has to be set up
  250.        before calling place_lregions etc. */
  251.     setup_waterlevel();
  252.     }
  253.     for(x = 0; x < num_lregions; x++, r++) {
  254.     switch(r->rtype) {
  255.     case LR_BRANCH:
  256.         added_branch = TRUE;
  257.         goto place_it;
  258.  
  259.     case LR_PORTAL:
  260.         if(*r->rname >= '0' && *r->rname <= '9') {
  261.         /* "chutes and ladders" */
  262.         lev = u.uz;
  263.         lev.dlevel = atoi(r->rname);
  264.         } else
  265.         lev = find_level(r->rname)->dlevel;
  266.         /* fall into... */
  267.  
  268.     case LR_UPSTAIR:
  269.     case LR_DOWNSTAIR:
  270.     place_it:
  271.         place_lregion(r->inarea.x1, r->inarea.y1,
  272.               r->inarea.x2, r->inarea.y2,
  273.               r->delarea.x1, r->delarea.y1,
  274.               r->delarea.x2, r->delarea.y2,
  275.               r->rtype, &lev);
  276.         break;
  277.  
  278.     case LR_TELE:
  279.     case LR_UPTELE:
  280.     case LR_DOWNTELE:
  281.         /* save the region outlines for goto_level() */
  282.         if(r->rtype == LR_TELE || r->rtype == LR_UPTELE) {
  283.             updest.lx = r->inarea.x1; updest.ly = r->inarea.y1;
  284.             updest.hx = r->inarea.x2; updest.hy = r->inarea.y2;
  285.             updest.nlx = r->delarea.x1; updest.nly = r->delarea.y1;
  286.             updest.nhx = r->delarea.x2; updest.nhy = r->delarea.y2;
  287.         }
  288.         if(r->rtype == LR_TELE || r->rtype == LR_DOWNTELE) {
  289.             dndest.lx = r->inarea.x1; dndest.ly = r->inarea.y1;
  290.             dndest.hx = r->inarea.x2; dndest.hy = r->inarea.y2;
  291.             dndest.nlx = r->delarea.x1; dndest.nly = r->delarea.y1;
  292.             dndest.nhx = r->delarea.x2; dndest.nhy = r->delarea.y2;
  293.         }
  294.         /* place_lregion gets called from goto_level() */
  295.         break;
  296.     }
  297.     }
  298.  
  299.     /* place dungeon branch if not placed above */
  300.     if (!added_branch && Is_branchlev(&u.uz)) {
  301.     place_lregion(0,0,0,0,0,0,0,0,LR_BRANCH,(d_level *)0);
  302.     }
  303.  
  304.     /* Still need to add some stuff to level file */
  305.     if (Is_medusa_level(&u.uz)) {
  306.     struct obj *otmp;
  307.     int tryct;
  308.  
  309.     croom = &rooms[0]; /* only one room on the medusa level */
  310.     for (tryct = rn1(1,3); tryct; tryct--) {
  311.         x = somex(croom); y = somey(croom);
  312.         if (goodpos(x, y, (struct monst *)0, (struct permonst *)0)) {
  313.         otmp = mk_tt_object(STATUE, x, y);
  314.         while (otmp && (poly_when_stoned(&mons[otmp->corpsenm]) ||
  315.                 resists_ston(&mons[otmp->corpsenm]))) {
  316.             otmp->corpsenm = rndmonnum();
  317.             otmp->owt = weight(otmp);
  318.         }
  319.         }
  320.     }
  321.  
  322.     if (rn2(2))
  323.         otmp = mk_tt_object(STATUE, somex(croom), somey(croom));
  324.     else /* Medusa statues don't contain books */
  325.         otmp = mkcorpstat(STATUE, (struct permonst *)0,
  326.                   somex(croom), somey(croom), FALSE);
  327.     if (otmp) {
  328.         while (resists_ston(&mons[otmp->corpsenm])
  329.            || poly_when_stoned(&mons[otmp->corpsenm])) {
  330.         otmp->corpsenm = rndmonnum();
  331.         otmp->owt = weight(otmp);
  332.         }
  333.     }
  334.     } else if(Is_wiz1_level(&u.uz)) {
  335.     croom = search_special(MORGUE);
  336.  
  337.     create_secret_door(croom, W_SOUTH|W_EAST|W_WEST);
  338. #ifdef MULDGN
  339.     } else if(Is_knox(&u.uz)) {
  340.     /* using an unfilled morgue for rm id */
  341.     croom = search_special(MORGUE);
  342.     /* stock the main vault */
  343.     for(x = croom->lx; x <= croom->hx; x++)
  344.         for(y = croom->ly; y <= croom->hy; y++) {
  345.         mkgold((long) rn1(300, 600), x, y);
  346.         if(!rn2(3) && !is_pool(x,y)) (void)maketrap(x, y, LANDMINE);
  347.         }
  348. #endif
  349.     } else if(Is_sanctum(&u.uz)) {
  350.     croom = search_special(TEMPLE);
  351.  
  352.     create_secret_door(croom, W_ANY);
  353.     } else if(on_level(&u.uz, &orcus_level)) {
  354.        register struct monst *mtmp, *mtmp2;
  355.  
  356.        /* it's a ghost town, get rid of shopkeepers */
  357.         for(mtmp = fmon; mtmp; mtmp = mtmp2) {
  358.             mtmp2 = mtmp->nmon;
  359.             if(mtmp->isshk) mongone(mtmp);
  360.         }
  361.     }
  362.  
  363.     if(lev_message) {
  364.     char *str, *nl;
  365.     for(str = lev_message; (nl = index(str, '\n')) != 0; str = nl+1) {
  366.         *nl = '\0';
  367.         pline("%s", str);
  368.     }
  369.     if(*str)
  370.         pline("%s", str);
  371.     free((genericptr_t)lev_message);
  372.     lev_message = 0;
  373.     }
  374. }
  375.  
  376. void
  377. makemaz(s)
  378. register const char *s;
  379. {
  380.     int x,y;
  381.     char protofile[20];
  382.     s_level    *sp = Is_special(&u.uz);
  383.     coord mm;
  384.  
  385.     if(*s) {
  386.         if(sp && sp->rndlevs) Sprintf(protofile, "%s-%d", s,
  387.                         rnd((int) sp->rndlevs));
  388.         else         Strcpy(protofile, s);
  389.     } else if(*(dungeons[u.uz.dnum].proto)) {
  390.         if(dunlevs_in_dungeon(&u.uz) > 1) {
  391.         if(sp && sp->rndlevs)
  392.              Sprintf(protofile, "%s%d-%d", dungeons[u.uz.dnum].proto,
  393.                         dunlev(&u.uz),
  394.                         rnd((int) sp->rndlevs));
  395.         else Sprintf(protofile, "%s%d", dungeons[u.uz.dnum].proto,
  396.                         dunlev(&u.uz));
  397.         } else if(sp && sp->rndlevs) {
  398.              Sprintf(protofile, "%s-%d", dungeons[u.uz.dnum].proto,
  399.                         rnd((int) sp->rndlevs));
  400.         } else Strcpy(protofile, dungeons[u.uz.dnum].proto);
  401.  
  402.     } else Strcpy(protofile, "");
  403.  
  404.     if(*protofile) {
  405.         Strcat(protofile, LEV_EXT);
  406.         if(load_special(protofile)) {
  407.         fixup_special();
  408.         return;    /* no mazification right now */
  409.         }
  410.         impossible("Couldn't load '%s' - making a maze.", protofile);
  411.     }
  412.  
  413.     level.flags.is_maze_lev = TRUE;
  414.  
  415. #ifndef WALLIFIED_MAZE
  416.     for(x = 2; x < x_maze_max; x++)
  417.         for(y = 2; y < y_maze_max; y++)
  418.             levl[x][y].typ = STONE;
  419. #else
  420.     for(x = 2; x <= x_maze_max; x++)
  421.         for(y = 2; y <= y_maze_max; y++)
  422.             levl[x][y].typ = ((x % 2) && (y % 2)) ? STONE : HWALL;
  423. #endif
  424.  
  425.     maze0xy(&mm);
  426.     walkfrom((int) mm.x, (int) mm.y);
  427.     /* put a boulder at the maze center */
  428.     (void) mksobj_at(BOULDER, (int) mm.x, (int) mm.y, TRUE);
  429.  
  430. #ifdef WALLIFIED_MAZE
  431.     wallification(2, 2, x_maze_max, y_maze_max);
  432. #else
  433.     for(x = 2; x < x_maze_max; x++)
  434.         for(y = 2; y < y_maze_max; y++)
  435.             levl[x][y].seen = 1;    /* start out seen */
  436. #endif
  437.     if(Invocation_lev(&u.uz)) {
  438.         place_lregion(0,0,0,0, 30, 0, 46, ROWNO, UP, (d_level *)0);
  439.         do {
  440.             if(xupstair < 30)
  441.                 x = rn1(COLNO-16-xupstair, xupstair+7);
  442.             else
  443.                 x = rn1(xupstair-16, 9);
  444.             y = rn1(7, 8);
  445.         } while((levl[x][y].typ != CORR && levl[x][y].typ != ROOM)
  446.             || occupied(x,y));
  447.         inv_pos.x = x;
  448.         inv_pos.y = y;
  449.     } else {
  450.         /* no regular up stairs on the first level of a dungeon) */
  451.         if(u.uz.dlevel != 1) {
  452.         mazexy(&mm);
  453.         mkstairs(mm.x, mm.y, UP, (struct mkroom *)0);
  454.         }
  455.  
  456.         /* no regular down stairs on the last level of a dungeon */
  457.         if(dunlev(&u.uz) != dunlevs_in_dungeon(&u.uz)) {
  458.         mazexy(&mm);
  459.         mkstairs(mm.x, mm.y, DOWN, (struct mkroom *)0);
  460.         }
  461.     }
  462.  
  463.     /* place branch stair or portal */
  464.     place_branch(Is_branchlev(&u.uz), 0, 0);
  465.  
  466.     for(x = rn1(8,11); x; x--) {
  467.         mazexy(&mm);
  468.         (void) mkobj_at(rn2(2) ? GEM_CLASS : 0, mm.x, mm.y, TRUE);
  469.     }
  470.     for(x = rn1(10,2); x; x--) {
  471.         mazexy(&mm);
  472.         (void) mksobj_at(BOULDER, mm.x, mm.y, TRUE);
  473.     }
  474.     mazexy(&mm);
  475.     (void) makemon(&mons[PM_MINOTAUR], mm.x, mm.y);
  476.     for(x = rn1(5,7); x; x--) {
  477.         mazexy(&mm);
  478.         (void) makemon((struct permonst *) 0, mm.x, mm.y);
  479.     }
  480.     for(x = rn1(6,7); x; x--) {
  481.         mazexy(&mm);
  482.         mkgold(0L,mm.x,mm.y);
  483.     }
  484.     for(x = rn1(6,7); x; x--)
  485.         mktrap(0,1,(struct mkroom *) 0, (coord*) 0);
  486. }
  487.  
  488. #ifdef MICRO
  489. /* Make the mazewalk iterative by faking a stack.  This is needed to
  490.  * ensure the mazewalk is successful in the limited stack space of
  491.  * the program.  This iterative version uses the minimum amount of stack
  492.  * that is totally safe.
  493.  */
  494. void
  495. walkfrom(x,y)
  496. int x,y;
  497. {
  498. #define CELLS (ROWNO * COLNO) / 4        /* a maze cell is 4 squares */
  499.     char mazex[CELLS + 1], mazey[CELLS + 1];    /* char's are OK */
  500.     int q, a, dir, pos;
  501.     int dirs[4];
  502.  
  503.     pos = 1;
  504.     mazex[pos] = (char) x;
  505.     mazey[pos] = (char) y;
  506.     while (pos) {
  507.         x = (int) mazex[pos];
  508.         y = (int) mazey[pos];
  509.         if(!IS_DOOR(levl[x][y].typ)) {
  510.             /* might still be on edge of MAP, so don't overwrite */
  511. #ifndef WALLIFIED_MAZE
  512.             levl[x][y].typ = CORR;
  513. #else
  514.             levl[x][y].typ = ROOM;
  515. #endif
  516.             levl[x][y].flags = 0;
  517.         }
  518.         q = 0;
  519.         for (a = 0; a < 4; a++)
  520.             if(okay(x, y, a)) dirs[q++]= a;
  521.         if (!q)
  522.             pos--;
  523.         else {
  524.             dir = dirs[rn2(q)];
  525.             move(&x, &y, dir);
  526. #ifndef WALLIFIED_MAZE
  527.             levl[x][y].typ = CORR;
  528. #else
  529.             levl[x][y].typ = ROOM;
  530. #endif
  531.             move(&x, &y, dir);
  532.             pos++;
  533.             if (pos > CELLS)
  534.                 panic("Overflow in walkfrom");
  535.             mazex[pos] = (char) x;
  536.             mazey[pos] = (char) y;
  537.         }
  538.     }
  539. }
  540. #else
  541.  
  542. void
  543. walkfrom(x,y)
  544. int x,y;
  545. {
  546.     register int q,a,dir;
  547.     int dirs[4];
  548.  
  549.     if(!IS_DOOR(levl[x][y].typ)) {
  550.         /* might still be on edge of MAP, so don't overwrite */
  551. #ifndef WALLIFIED_MAZE
  552.         levl[x][y].typ = CORR;
  553. #else
  554.         levl[x][y].typ = ROOM;
  555. #endif
  556.         levl[x][y].flags = 0;
  557.     }
  558.  
  559.     while(1) {
  560.         q = 0;
  561.         for(a = 0; a < 4; a++)
  562.             if(okay(x,y,a)) dirs[q++]= a;
  563.         if(!q) return;
  564.         dir = dirs[rn2(q)];
  565.         move(&x,&y,dir);
  566. #ifndef WALLIFIED_MAZE
  567.         levl[x][y].typ = CORR;
  568. #else
  569.         levl[x][y].typ = ROOM;
  570. #endif
  571.         move(&x,&y,dir);
  572.         walkfrom(x,y);
  573.     }
  574. }
  575. #endif /* MICRO */
  576.  
  577. void
  578. move(x,y,dir)
  579. register int *x, *y;
  580. register int dir;
  581. {
  582.     switch(dir){
  583.         case 0: --(*y); break;
  584.         case 1: (*x)++; break;
  585.         case 2: (*y)++; break;
  586.         case 3: --(*x); break;
  587.     }
  588. }
  589.  
  590. void
  591. mazexy(cc)    /* find random point in generated corridors,
  592.            so we don't create items in moats, bunkers, or walls */
  593.     coord    *cc;
  594. {
  595.     int cpt=0;
  596.  
  597.     do {
  598.         cc->x = 3 + 2*rn2((x_maze_max>>1) - 1);
  599.         cc->y = 3 + 2*rn2((y_maze_max>>1) - 1);
  600.         cpt++;
  601.     } while (cpt < 100 && levl[cc->x][cc->y].typ !=
  602. #ifndef WALLIFIED_MAZE
  603.          CORR
  604. #else
  605.          ROOM
  606. #endif
  607.         );
  608.     if (cpt >= 100) {
  609.         register int x, y;
  610.         /* last try */
  611.         for (x = 0; x < (x_maze_max>>1) - 1; x++)
  612.             for (y = 0; y < (y_maze_max>>1) - 1; y++) {
  613.             cc->x = 3 + 2 * x;
  614.             cc->y = 3 + 2 * y;
  615.             if (levl[cc->x][cc->y].typ ==
  616. #ifndef WALLIFIED_MAZE
  617.                 CORR
  618. #else
  619.                 ROOM
  620. #endif
  621.                ) return;
  622.             }
  623.         panic("mazexy: can't find a place!");
  624.     }
  625.     return;
  626. }
  627.  
  628. void
  629. bound_digging()
  630. /* put a non-diggable boundary around the initial portion of a level map.
  631.  * assumes that no level will initially put things beyond the isok() range.
  632.  *
  633.  * we can't bound unconditionally on the last line with something in it,
  634.  * because that something might be a niche which was already reachable,
  635.  * so the boundary would be breached
  636.  *
  637.  * we can't bound unconditionally on one beyond the last line, because
  638.  * that provides a window of abuse for WALLIFIED_MAZE special levels
  639.  */
  640. {
  641.     register int x,y;
  642.     register unsigned typ;
  643.     register struct rm *lev;
  644.     boolean found, nonwall;
  645.     int xmin,xmax,ymin,ymax;
  646.  
  647.     if(Is_earthlevel(&u.uz)) return; /* everything diggable here */
  648.  
  649.     found = nonwall = FALSE;
  650.     for(xmin=0; !found; xmin++) {
  651.         lev = &levl[xmin][0];
  652.         for(y=0; y<=ROWNO-1; y++, lev++) {
  653.             typ = lev->typ;
  654.             if(typ != STONE) {
  655.                 found = TRUE;
  656.                 if(!IS_WALL(typ)) nonwall = TRUE;
  657.             }
  658.         }
  659.     }
  660.     xmin -= (nonwall || !level.flags.is_maze_lev) ? 2 : 1;
  661.     if (xmin < 0) xmin = 0;
  662.  
  663.     found = nonwall = FALSE;
  664.     for(xmax=COLNO-1; !found; xmax--) {
  665.         lev = &levl[xmax][0];
  666.         for(y=0; y<=ROWNO-1; y++, lev++) {
  667.             typ = lev->typ;
  668.             if(typ != STONE) {
  669.                 found = TRUE;
  670.                 if(!IS_WALL(typ)) nonwall = TRUE;
  671.             }
  672.         }
  673.     }
  674.     xmax += (nonwall || !level.flags.is_maze_lev) ? 2 : 1;
  675.     if (xmax >= COLNO) xmax = COLNO-1;
  676.  
  677.     found = nonwall = FALSE;
  678.     for(ymin=0; !found; ymin++) {
  679.         lev = &levl[xmin][ymin];
  680.         for(x=xmin; x<=xmax; x++, lev += ROWNO) {
  681.             typ = lev->typ;
  682.             if(typ != STONE) {
  683.                 found = TRUE;
  684.                 if(!IS_WALL(typ)) nonwall = TRUE;
  685.             }
  686.         }
  687.     }
  688.     ymin -= (nonwall || !level.flags.is_maze_lev) ? 2 : 1;
  689.  
  690.     found = nonwall = FALSE;
  691.     for(ymax=ROWNO-1; !found; ymax--) {
  692.         lev = &levl[xmin][ymax];
  693.         for(x=xmin; x<=xmax; x++, lev += ROWNO) {
  694.             typ = lev->typ;
  695.             if(typ != STONE) {
  696.                 found = TRUE;
  697.                 if(!IS_WALL(typ)) nonwall = TRUE;
  698.             }
  699.         }
  700.     }
  701.     ymax += (nonwall || !level.flags.is_maze_lev) ? 2 : 1;
  702.  
  703.     if(ymin >= 0)
  704.         for(x=xmin; x<=xmax; x++) levl[x][ymin].diggable = W_NONDIGGABLE;
  705.     if(ymax < ROWNO)
  706.         for(x=xmin; x<=xmax; x++) levl[x][ymax].diggable = W_NONDIGGABLE;
  707.  
  708.     /* Don't bound these until _after_ the previous loops to avoid "ice" */
  709.     /* Normal rooms become ice by setting W_NONDIGGABLE -dlc */
  710.     if (ymin < 0) ymin = 0;
  711.     if (ymax >= ROWNO) ymax = ROWNO-1;
  712.  
  713.     for(y=ymin; y<=ymax; y++) {
  714.         levl[xmin][y].diggable = W_NONDIGGABLE;
  715.         levl[xmax][y].diggable = W_NONDIGGABLE;
  716.     }
  717. }
  718.  
  719. void
  720. mkportal(x, y, todnum, todlevel)
  721. register xchar x, y, todnum, todlevel;
  722. {
  723.     /* a portal "trap" must be matched by a */
  724.     /* portal in the destination dungeon/dlevel */
  725.     register struct trap *ttmp = maketrap(x, y, MAGIC_PORTAL);
  726.  
  727. #ifdef DEBUG
  728.     pline("mkportal: at (%d,%d), to %s, level %d",
  729.         x, y, dungeons[todnum].dname, todlevel);
  730. #endif
  731.     ttmp->dst.dnum = todnum;
  732.     ttmp->dst.dlevel = todlevel;
  733.     return;
  734. }
  735.  
  736. /*
  737.  * Special waterlevel stuff in endgame (TH).
  738.  *
  739.  * Some of these functions would probably logically belong to some
  740.  * other source files, but they are all so nicely encapsulated here.
  741.  */
  742.  
  743. /* to ease the work of debuggers at this stage */
  744. #define register
  745.  
  746. struct container {
  747.     struct container *next;
  748.     xchar x, y;
  749.     short what;
  750.     genericptr_t list;
  751. };
  752. #define CONS_OBJ   0
  753. #define CONS_MON   1
  754. #define CONS_HERO  2
  755. #define CONS_TRAP  3
  756.  
  757. static struct bubble {
  758.     xchar x, y;    /* coordinates of the upper left corner */
  759.     schar dx, dy;    /* the general direction of the bubble's movement */
  760.     uchar *bm;    /* pointer to the bubble bit mask */
  761.     struct bubble *prev, *next; /* need to traverse the list up and down */
  762.     struct container *cons;
  763. } *bbubbles, *ebubbles;
  764.  
  765. static struct trap *wportal;
  766. static int xmin, ymin, xmax, ymax;    /* level boundaries */
  767. /* bubble movement boundaries */
  768. #define bxmin (xmin + 1)
  769. #define bymin (ymin + 1)
  770. #define bxmax (xmax - 1)
  771. #define bymax (ymax - 1)
  772.  
  773. static void NDECL(set_wportal);
  774. static void FDECL(mk_bubble, (int,int,int));
  775. static void FDECL(mv_bubble, (struct bubble *,int,int,BOOLEAN_P));
  776.  
  777. void
  778. movebubbles()
  779. {
  780.     static boolean up;
  781.     register struct bubble *b;
  782.     register int x, y, i, j;
  783.     struct trap *btrap;
  784.     static const struct rm water_pos =
  785.         { cmap_to_glyph(S_water), WATER, 0, 0, 0, 0, 0, 0, 0 };
  786.  
  787.     /* set up the portal the first time bubbles are moved */
  788.     if (!wportal) set_wportal();
  789.  
  790.     vision_recalc(2);
  791.  
  792.     /*
  793.      * Pick up everything inside of a bubble then fill all bubble
  794.      * locations.
  795.      */
  796.  
  797.     for (b = up ? bbubbles : ebubbles; b; b = up ? b->next : b->prev) {
  798.         if (b->cons) panic("movebubbles: cons != null");
  799.         for (i = 0, x = b->x; i < (int) b->bm[0]; i++, x++)
  800.         for (j = 0, y = b->y; j < (int) b->bm[1]; j++, y++)
  801.             if (b->bm[j + 2] & (1 << i)) {
  802.             if (!isok(x,y)) {
  803.                 impossible("movebubbles: bad pos (%d,%d)", x,y);
  804.                 continue;
  805.             }
  806.  
  807.             /* pick up objects, monsters, hero, and traps */
  808.             if (OBJ_AT(x,y)) {
  809.                 struct obj *olist = (struct obj *) 0, *otmp;
  810.                 struct container *cons = (struct container *)
  811.                 alloc(sizeof(struct container));
  812.  
  813.                 while ((otmp = level.objects[x][y]) != 0) {
  814.                 remove_object(otmp);
  815.                 otmp->ox = otmp->oy = 0;
  816.                 otmp->nexthere = olist;
  817.                 olist = otmp;
  818.                 }
  819.  
  820.                 cons->x = x;
  821.                 cons->y = y;
  822.                 cons->what = CONS_OBJ;
  823.                 cons->list = (genericptr_t) olist;
  824.                 cons->next = b->cons;
  825.                 b->cons = cons;
  826.             }
  827.             if (MON_AT(x,y)) {
  828.                 struct monst *mon = m_at(x,y);
  829.                 struct container *cons = (struct container *)
  830.                 alloc(sizeof(struct container));
  831.  
  832.                 cons->x = x;
  833.                 cons->y = y;
  834.                 cons->what = CONS_MON;
  835.                 cons->list = (genericptr_t) mon;
  836.  
  837.                 cons->next = b->cons;
  838.                 b->cons = cons;
  839.  
  840.                 if(mon->wormno)
  841.                 remove_worm(mon);
  842.                 else
  843.                 remove_monster(x, y);
  844.  
  845.                 newsym(x,y);    /* clean up old position */
  846.                 mon->mx = mon->my = 0;
  847.             }
  848.             if (!u.uswallow && x == u.ux && y == u.uy) {
  849.                 struct container *cons = (struct container *)
  850.                 alloc(sizeof(struct container));
  851.  
  852.                 cons->x = x;
  853.                 cons->y = y;
  854.                 cons->what = CONS_HERO;
  855.                 cons->list = (genericptr_t) 0;
  856.  
  857.                 cons->next = b->cons;
  858.                 b->cons = cons;
  859.             }
  860.             if ((btrap = t_at(x,y)) != 0) {
  861.                 struct container *cons = (struct container *)
  862.                 alloc(sizeof(struct container));
  863.  
  864.                 cons->x = x;
  865.                 cons->y = y;
  866.                 cons->what = CONS_TRAP;
  867.                 cons->list = (genericptr_t) btrap;
  868.  
  869.                 cons->next = b->cons;
  870.                 b->cons = cons;
  871.             }
  872.  
  873.             levl[x][y] = water_pos;
  874.             block_point(x,y);
  875.             }
  876.     }
  877.  
  878.     /*
  879.      * Every second time traverse down.  This is because otherwise
  880.      * all the junk that changes owners when bubbles overlap
  881.      * would eventually end up in the last bubble in the chain.
  882.      */
  883.  
  884.     up = !up;
  885.     for (b = up ? bbubbles : ebubbles; b; b = up ? b->next : b->prev) {
  886.         register int rx = rn2(3), ry = rn2(3);
  887.  
  888.         mv_bubble(b,b->dx + 1 - (!b->dx ? rx : (rx ? 1 : 0)),
  889.                 b->dy + 1 - (!b->dy ? ry : (ry ? 1 : 0)),
  890.                 FALSE);
  891.     }
  892.  
  893.     vision_full_recalc = 1;
  894. }
  895.  
  896. void
  897. water_friction()
  898. {
  899.     register boolean eff = FALSE;
  900.  
  901.     if (u.dx && !rn2(3)) {
  902.         eff = TRUE;
  903.         u.dx = 0;
  904.     }
  905.     if (u.dy && !rn2(3)) {
  906.         eff = TRUE;
  907.         u.dy = 0;
  908.     }
  909.     if (eff) pline("Water turbulence affects your movements.");
  910. }
  911.  
  912. void
  913. save_waterlevel(fd)
  914. register int fd;
  915. {
  916.     register struct bubble *b;
  917.     int n;
  918.  
  919.     if (!Is_waterlevel(&u.uz)) return;
  920.  
  921.     for (b = bbubbles, n = 0; b; b = b->next, n++) ;
  922.     bwrite(fd,(genericptr_t)&n,sizeof(int));
  923.     bwrite(fd,(genericptr_t)&xmin,sizeof(int));
  924.     bwrite(fd,(genericptr_t)&ymin,sizeof(int));
  925.     bwrite(fd,(genericptr_t)&xmax,sizeof(int));
  926.     bwrite(fd,(genericptr_t)&ymax,sizeof(int));
  927.     for (b = bbubbles; b; b = b->next)
  928.         bwrite(fd,(genericptr_t)b,sizeof(struct bubble));
  929. }
  930.  
  931. void
  932. restore_waterlevel(fd)
  933. register int fd;
  934. {
  935.     register struct bubble *b = (struct bubble *)0, *btmp;
  936.     register int i;
  937.     int n;
  938.  
  939.     if (!Is_waterlevel(&u.uz)) return;
  940.  
  941.     set_wportal();
  942.     mread(fd,(genericptr_t)&n,sizeof(int));
  943.     mread(fd,(genericptr_t)&xmin,sizeof(int));
  944.     mread(fd,(genericptr_t)&ymin,sizeof(int));
  945.     mread(fd,(genericptr_t)&xmax,sizeof(int));
  946.     mread(fd,(genericptr_t)&ymax,sizeof(int));
  947.     for (i = 0; i < n; i++) {
  948.         btmp = b;
  949.         b = (struct bubble *)alloc(sizeof(struct bubble));
  950.         mread(fd,(genericptr_t)b,sizeof(struct bubble));
  951.         if (bbubbles) {
  952.             btmp->next = b;
  953.             b->prev = btmp;
  954.         } else {
  955.             bbubbles = b;
  956.             b->prev = (struct bubble *)0;
  957.         }
  958.         mv_bubble(b,0,0,TRUE);
  959.     }
  960.     ebubbles = b;
  961.     b->next = (struct bubble *)0;
  962.     was_waterlevel = TRUE;
  963. }
  964.  
  965. static void
  966. set_wportal()
  967. {
  968.     /* there better be only one magic portal on water level... */
  969.     for (wportal = ftrap; wportal; wportal = wportal->ntrap)
  970.         if (wportal->ttyp == MAGIC_PORTAL) return;
  971.     impossible("set_wportal(): no portal!");
  972. }
  973.  
  974. static void
  975. setup_waterlevel()
  976. {
  977.     register int x, y;
  978.     register int xskip, yskip;
  979.     register int water_glyph = cmap_to_glyph(S_water);
  980.  
  981.     /* ouch, hardcoded... */
  982.  
  983.     xmin = 3;
  984.     ymin = 1;
  985.     xmax = 78;
  986.     ymax = 20;
  987.  
  988.     /* set hero's memory to water */
  989.  
  990.     for (x = xmin; x <= xmax; x++)
  991.         for (y = ymin; y <= ymax; y++)
  992.             levl[x][y].glyph = water_glyph;
  993.  
  994.     /* make bubbles */
  995.  
  996.     xskip = 10 + rn2(10);
  997.     yskip = 4 + rn2(4);
  998.     for (x = bxmin; x <= bxmax; x += xskip)
  999.         for (y = bymin; y <= bymax; y += yskip)
  1000.             mk_bubble(x,y,rn2(7));
  1001. }
  1002.  
  1003. static void
  1004. unsetup_waterlevel()
  1005. {
  1006.     register struct bubble *b, *bb;
  1007.  
  1008.     /* free bubbles */
  1009.  
  1010.     for (b = bbubbles; b; b = bb) {
  1011.         bb = b->next;
  1012.         free((genericptr_t)b);
  1013.     }
  1014.     bbubbles = ebubbles = (struct bubble *)0;
  1015. }
  1016.  
  1017. static void
  1018. mk_bubble(x,y,n)
  1019. register int x, y, n;
  1020. {
  1021.     /*
  1022.      * These bit masks make visually pleasing bubbles on a normal aspect
  1023.      * 25x80 terminal, which naturally results in them being mathematically
  1024.      * anything but symmetric.  For this reason they cannot be computed
  1025.      * in situ, either.  The first two elements tell the dimensions of
  1026.      * the bubble's bounding box.
  1027.      */
  1028.     static uchar
  1029.         bm2[] = {2,1,0x3},
  1030.         bm3[] = {3,2,0x7,0x7},
  1031.         bm4[] = {4,3,0x6,0xf,0x6},
  1032.         bm5[] = {5,3,0xe,0x1f,0xe},
  1033.         bm6[] = {6,4,0x1e,0x3f,0x3f,0x1e},
  1034.         bm7[] = {7,4,0x3e,0x7f,0x7f,0x3e},
  1035.         bm8[] = {8,4,0x7e,0xff,0xff,0x7e},
  1036.         *bmask[] = {bm2,bm3,bm4,bm5,bm6,bm7,bm8};
  1037.  
  1038.     register struct bubble *b;
  1039.  
  1040.     if (x >= bxmax || y >= bymax) return;
  1041.     if (n >= SIZE(bmask)) {
  1042.         impossible("n too large (mk_bubble)");
  1043.         n = SIZE(bmask) - 1;
  1044.     }
  1045.     b = (struct bubble *)alloc(sizeof(struct bubble));
  1046.     if ((x + (int) bmask[n][0] - 1) > bxmax) x = bxmax - bmask[n][0] + 1;
  1047.     if ((y + (int) bmask[n][1] - 1) > bymax) y = bymax - bmask[n][1] + 1;
  1048.     b->x = x;
  1049.     b->y = y;
  1050.     b->dx = 1 - rn2(3);
  1051.     b->dy = 1 - rn2(3);
  1052.     b->bm = bmask[n];
  1053.     b->cons = 0;
  1054.     if (!bbubbles) bbubbles = b;
  1055.     if (ebubbles) {
  1056.         ebubbles->next = b;
  1057.         b->prev = ebubbles;
  1058.     }
  1059.     else
  1060.         b->prev = (struct bubble *)0;
  1061.     b->next =  (struct bubble *)0;
  1062.     ebubbles = b;
  1063.     mv_bubble(b,0,0,TRUE);
  1064. }
  1065.  
  1066. /*
  1067.  * The player, the portal and all other objects and monsters
  1068.  * float along with their associated bubbles.  Bubbles may overlap
  1069.  * freely, and the contents may get associated with other bubbles in
  1070.  * the process.  Bubbles are "sticky", meaning that if the player is
  1071.  * in the immediate neighborhood of one, he/she may get sucked inside.
  1072.  * This property also makes leaving a bubble slightly difficult.
  1073.  */
  1074. static void
  1075. mv_bubble(b,dx,dy,ini)
  1076. register struct bubble *b;
  1077. register int dx, dy;
  1078. register boolean ini;
  1079. {
  1080.     register int x, y, i, j, colli = 0;
  1081.     struct bubble ob;
  1082.     struct container *cons, *ctemp;
  1083.  
  1084.     /* some old data for reference */
  1085.  
  1086.     ob.x = b->x;
  1087.     ob.y = b->y;
  1088.     ob.bm = b->bm;
  1089.  
  1090.     /* move bubble */
  1091.     if (dx < -1 || dx > 1 || dy < -1 || dy > 1) {
  1092.         /* pline("mv_bubble: dx = %d, dy = %d", dx, dy); */
  1093.         dx = sgn(dx);
  1094.         dy = sgn(dy);
  1095.     }
  1096.  
  1097.     /*
  1098.      * collision with level borders?
  1099.      *    1 = horizontal border, 2 = vertical, 3 = corner
  1100.      */
  1101.     if (b->x <= bxmin) colli |= 2;
  1102.     if (b->y <= bymin) colli |= 1;
  1103.     if ((int) (b->x + b->bm[0] - 1) >= bxmax) colli |= 2;
  1104.     if ((int) (b->y + b->bm[1] - 1) >= bymax) colli |= 1;
  1105.  
  1106.     if (b->x < bxmin) {
  1107.         pline("bubble xmin: x = %d, xmin = %d", b->x, bxmin);
  1108.         b->x = bxmin;
  1109.     }
  1110.     if (b->y < bymin) {
  1111.         pline("bubble ymin: y = %d, ymin = %d", b->y, bymin);
  1112.         b->y = bymin;
  1113.     }
  1114.     if ((int) (b->x + b->bm[0] - 1) > bxmax) {
  1115.         pline("bubble xmax: x = %d, xmax = %d",
  1116.             b->x + b->bm[0] - 1, bxmax);
  1117.         b->x = bxmax - b->bm[0] + 1;
  1118.     }
  1119.     if ((int) (b->y + b->bm[1] - 1) > bymax) {
  1120.         pline("bubble ymax: y = %d, ymax = %d",
  1121.             b->y + b->bm[1] - 1, bymax);
  1122.         b->y = bymax - b->bm[1] + 1;
  1123.     }
  1124.  
  1125.     /* bounce if we're trying to move off the border */
  1126.     if (b->x == bxmin && dx < 0) dx = -dx;
  1127.     if (b->x + b->bm[0] - 1 == bxmax && dx > 0) dx = -dx;
  1128.     if (b->y == bymin && dy < 0) dy = -dy;
  1129.     if (b->y + b->bm[1] - 1 == bymax && dy > 0) dy = -dy;
  1130.  
  1131.     b->x += dx;
  1132.     b->y += dy;
  1133.  
  1134.     /* void positions inside bubble */
  1135.  
  1136.     for (i = 0, x = b->x; i < (int) b->bm[0]; i++, x++)
  1137.         for (j = 0, y = b->y; j < (int) b->bm[1]; j++, y++)
  1138.         if (b->bm[j + 2] & (1 << i)) {
  1139.             levl[x][y].typ = AIR;
  1140.             levl[x][y].lit = 1;
  1141.             unblock_point(x,y);
  1142.         }
  1143.  
  1144.     /* replace contents of bubble */
  1145.     for (cons = b->cons; cons; cons = ctemp) {
  1146.         ctemp = cons->next;
  1147.         cons->x += dx;
  1148.         cons->y += dy;
  1149.  
  1150.         switch(cons->what) {
  1151.         case CONS_OBJ: {
  1152.             struct obj *olist, *otmp;
  1153.  
  1154.             for (olist=(struct obj *)cons->list; olist; olist=otmp) {
  1155.             otmp = olist->nexthere;
  1156.             place_object(olist, cons->x, cons->y);
  1157.             }
  1158.             break;
  1159.         }
  1160.  
  1161.         case CONS_MON: {
  1162.             struct monst *mon = (struct monst *) cons->list;
  1163.             (void) mnearto(mon, cons->x, cons->y, TRUE);
  1164.             break;
  1165.         }
  1166.  
  1167.         case CONS_HERO: {
  1168.             int ux0 = u.ux, uy0 = u.uy;
  1169.  
  1170.             /* change u.ux0 and u.uy0? */
  1171.             u.ux = cons->x;
  1172.             u.uy = cons->y;
  1173.             newsym(ux0, uy0);    /* clean up old position */
  1174.  
  1175.             if (MON_AT(cons->x, cons->y)) {
  1176.                 mnexto(m_at(cons->x,cons->y));
  1177.             }
  1178.             if (Punished) placebc();    /* do this for now */
  1179.             break;
  1180.         }
  1181.  
  1182.         case CONS_TRAP: {
  1183.             struct trap *btrap = (struct trap *) cons->list;
  1184.             btrap->tx = cons->x;
  1185.             btrap->ty = cons->y;
  1186.             break;
  1187.         }
  1188.  
  1189.         default:
  1190.             impossible("mv_bubble: unknown bubble contents");
  1191.             break;
  1192.         }
  1193.         free((genericptr_t)cons);
  1194.     }
  1195.     b->cons = 0;
  1196.  
  1197.     /* boing? */
  1198.  
  1199.     switch (colli) {
  1200.         case 1: b->dy = -b->dy;    break;
  1201.         case 3: b->dy = -b->dy;    /* fall through */
  1202.         case 2: b->dx = -b->dx;    break;
  1203.         default:
  1204.         /* sometimes alter direction for fun anyway
  1205.            (higher probability for stationary bubbles) */
  1206.         if (!ini && ((b->dx || b->dy) ? !rn2(20) : !rn2(5))) {
  1207.             b->dx = 1 - rn2(3);
  1208.             b->dy = 1 - rn2(3);
  1209.         }
  1210.     }
  1211. }
  1212.  
  1213.  
  1214. /*mkmaze.c*/
  1215.